import os
import time

from battleship import Battleship
from board import Board
from carrier import Carrier
from common import PlaceResult, AttackResult
from destroyer import Destroyer
from player import Player
from ship import Ship
from submarine import Submarine
from input import Input
from output import Output


class Game:
    def __init__(self, input, output, num_of_players):
        self.__input = input
        self.__output = output
        self.__num_of_players = num_of_players
        self.__players = []

    # 游戏开始
    def start(self) -> None:
        self.fill_info()
        self.player_attacks()

    # 创建地图
    def fill_info(self) -> None:
        for _ in range(self.get_num_of_players()):
            my_board = Board()
            en_board = Board()
            player = self.init_player(my_board, en_board)
            self.__players.append(player)
            self.place_ships(player)
            os.system('cls')

    # 创建玩家
    def init_player(self, my_board, en_board) -> Player:
        name = self.get_input().get_name()
        return Player(name, my_board, en_board)

    # 指引玩家放置ship
    def place_ships(self, player) -> None:
        carrier = Carrier()
        self.place_ship(player, carrier, True)
        battleship = Battleship()
        self.place_ship(player, battleship, False)
        destroyer = Destroyer()
        self.place_ship(player, destroyer, False)
        submarine = Submarine()
        self.place_ship(player, submarine, False)

    # 放置单个ship
    def place_ship(self, player, ship, is_new_game) -> None:
        cmd = self.get_input().get_place_ship(ship, is_new_game)
        place_result = player.place_ship(ship, cmd)
        while place_result != PlaceResult.SUCCESS:
            self.get_output().print_place_error(place_result)
            cmd = self.get_input().get_place_ship(ship, True)
            place_result = player.place_ship(ship, cmd)
        self.get_output().print_board(player.get_my_board())

    # 玩家轮流攻击
    def player_attacks(self) -> None:
        while True:
            for i in range(self.get_num_of_players()):
                player = self.get_players()[i]
                self.get_output().print_board(player.get_en_board())
                self.get_output().print_alert_attack(player)
                point = self.get_input().get_attack_point()
                target_board = self.get_enemy(i).get_my_board()
                attack_result, ship = self.attack(player.get_en_board(),
                                                  target_board, point)
                if attack_result == AttackResult.MISS:
                    time.sleep(1)
                    os.system('cls')
                    continue
                if attack_result == AttackResult.HIT:
                    self.get_output().show_hit()
                if attack_result == AttackResult.SUNK:
                    self.get_output().show_sunk(ship)
                if attack_result == AttackResult.GAME_OVER:
                    self.get_output().print_game_over(ship)
                    time.sleep(2)
                    return
                time.sleep(1)
                os.system('cls')

    # 模拟攻击
    @staticmethod
    def attack(attacker_board, target_board, point) -> (AttackResult, Ship):
        if not target_board.exist_ship(point):
            attacker_board.update_point(point, 'M')
            return AttackResult.MISS, Ship()
        attacker_board.update_point(point, 'X')
        return target_board.be_attacked_at(point)

    # 获得敌人
    def get_enemy(self, index) -> Player:
        return self.get_players()[self.get_num_of_players() - 1 - index]

    # 判断游戏是否结束
    @staticmethod
    def is_game_over(board) -> bool:
        return board.is_game_over()

    # 返回input属性
    def get_input(self) -> Input:
        return self.__input

    # 返回output属性
    def get_output(self) -> Output:
        return self.__output

    # 返回num_of_players属性
    def get_num_of_players(self) -> int:
        return self.__num_of_players

    # 返回players属性
    def get_players(self) -> list:
        return self.__players
